package dev.selenium.actions_api;

import dev.selenium.BaseChromeTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PenTest extends BaseChromeTest {
    @Test
    public void usePen() {
        driver.get("https://www.selenium.dev/selenium/web/pointerActionsPage.html");

        WebElement pointerArea = driver.findElement(By.id("pointerArea"));
        new Actions(driver)
                .setActivePointer(PointerInput.Kind.PEN, "default pen")
                .moveToElement(pointerArea)
                .clickAndHold()
                .moveByOffset(2, 2)
                .release()
                .perform();

        List<WebElement> moves = driver.findElements(By.className("pointermove"));
        Map<String, String> moveTo = getPropertyInfo(moves.get(0));
        Map<String, String> down = getPropertyInfo(driver.findElement(By.className("pointerdown")));
        Map<String, String> moveBy = getPropertyInfo(moves.get(1));
        Map<String, String> up = getPropertyInfo(driver.findElement(By.className("pointerup")));

        Rectangle rect = pointerArea.getRect();

        int centerX = (int) Math.floor(rect.width / 2 + rect.getX());
        int centerY = (int) Math.floor(rect.height / 2 + rect.getY());
        Assertions.assertEquals("-1", moveTo.get("button"));
        Assertions.assertEquals("pen", moveTo.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX), moveTo.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY), moveTo.get("pageY"));
        Assertions.assertEquals("0", down.get("button"));
        Assertions.assertEquals("pen", down.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX), down.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY), down.get("pageY"));
        Assertions.assertEquals("-1", moveBy.get("button"));
        Assertions.assertEquals("pen", moveBy.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX + 2), moveBy.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY + 2), moveBy.get("pageY"));
        Assertions.assertEquals("0", up.get("button"));
        Assertions.assertEquals("pen", up.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX + 2), up.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY + 2), up.get("pageY"));
    }

    @Test
    public void setPointerEventProperties() {
        driver.get("https://selenium.dev/selenium/web/pointerActionsPage.html");

        WebElement pointerArea = driver.findElement(By.id("pointerArea"));
        PointerInput pen = new PointerInput(PointerInput.Kind.PEN, "default pen");
        PointerInput.PointerEventProperties eventProperties = PointerInput.eventProperties()
                .setTiltX(-72)
                .setTiltY(9)
                .setTwist(86);
        PointerInput.Origin origin = PointerInput.Origin.fromElement(pointerArea);

        Sequence actionListPen = new Sequence(pen, 0)
                .addAction(pen.createPointerMove(Duration.ZERO, origin, 0, 0))
                .addAction(pen.createPointerDown(0))
                .addAction(pen.createPointerMove(Duration.ZERO, origin, 2, 2, eventProperties))
                .addAction(pen.createPointerUp(0));

        ((RemoteWebDriver) driver).perform(Collections.singletonList(actionListPen));

        List<WebElement> moves = driver.findElements(By.className("pointermove"));
        Map<String, String> moveTo = getPropertyInfo(moves.get(0));
        Map<String, String> down = getPropertyInfo(driver.findElement(By.className("pointerdown")));
        Map<String, String> moveBy = getPropertyInfo(moves.get(1));
        Map<String, String> up = getPropertyInfo(driver.findElement(By.className("pointerup")));

        Rectangle rect = pointerArea.getRect();
        int centerX = (int) Math.floor(rect.width / 2 + rect.getX());
        int centerY = (int) Math.floor(rect.height / 2 + rect.getY());
        Assertions.assertEquals("-1", moveTo.get("button"));
        Assertions.assertEquals("pen", moveTo.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX), moveTo.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY), moveTo.get("pageY"));
        Assertions.assertEquals("0", down.get("button"));
        Assertions.assertEquals("pen", down.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX), down.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY), down.get("pageY"));
        Assertions.assertEquals("-1", moveBy.get("button"));
        Assertions.assertEquals("pen", moveBy.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX + 2), moveBy.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY + 2), moveBy.get("pageY"));
        Assertions.assertEquals("-72", moveBy.get("tiltX"));
        Assertions.assertEquals("9", moveBy.get("tiltY"));
        Assertions.assertEquals("86", moveBy.get("twist"));
        Assertions.assertEquals("0", up.get("button"));
        Assertions.assertEquals("pen", up.get("pointerType"));
        Assertions.assertEquals(String.valueOf(centerX + 2), up.get("pageX"));
        Assertions.assertEquals(String.valueOf(centerY + 2), up.get("pageY"));
    }

    private Map<String, String> getPropertyInfo(WebElement element) {
        String text = element.getText();
        text = text.substring(text.indexOf(' ') + 1);

        return Arrays.stream(text.split(", "))
                .map(s -> s.split(": "))
                .collect(Collectors.toMap(
                        a -> a[0],
                        a -> a[1]
                ));
    }
}
